package com.spzx.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.spzx.common.core.utils.bean.BeanUtils;
import com.spzx.product.domain.Category;
import com.spzx.product.mapper.CategoryMapper;
import com.spzx.product.service.ICategoryService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spzx.product.vo.CategoryVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 商品分类 服务实现类
 * </p>
 *
 * @author atguigu
 * @since 2024-12-20
 */
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements ICategoryService {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Category> treeSelect(Long parentId) {
        LambdaQueryWrapper<Category> categoryLambdaQueryWrapper = new LambdaQueryWrapper<>();
        categoryLambdaQueryWrapper.eq(Category::getParentId,parentId);
        List<Category> categoryList = baseMapper.selectList(categoryLambdaQueryWrapper);
        categoryList.forEach( category -> {
            LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Category::getParentId,category.getId());
            Long count = baseMapper.selectCount(queryWrapper);
            category.setHasChildren(count > 0);
        });
        return categoryList;
    }

    @Override
    public List<CategoryVo> getLevelOneCategory() {
        List<Category> categoryList = baseMapper.selectList(
                new LambdaQueryWrapper<Category>().eq(Category::getParentId, 0)
        );
        List<CategoryVo> categoryVoList = categoryList.stream().map(category -> {
            CategoryVo categoryVo = new CategoryVo();
            BeanUtils.copyProperties(category, categoryVo);
            return categoryVo;
        }).toList();
        return categoryVoList;
    }

    @Override
    public List<CategoryVo> tree() {
        //先查询出全部的分类对象
        List<Category> categoryList = baseMapper.selectList(null);
        //将这个List中的所有Category对象转化为CategoryVo对象
        List<CategoryVo> categoryVoList = categoryList.stream().map(category -> {
            CategoryVo categoryVo = new CategoryVo();
            BeanUtils.copyProperties(category, categoryVo);
            return categoryVo;
        }).toList();
        /**
         * 这里我们使用buildTree()方法，将categoryVoList传入
         * 我们将在这个方法中，遍历categoryVolist，并且为其中的每一个categoryVo对象设置children属性
         * 最后将组装完备List集合返回回来
         */
        return buildTree(categoryVoList);
    }

    /**
     * 将categoryVoList中的categoryVo组装children属性，并返回
     * @param categoryVoList Vo集合
     * @return
     */
    private List<CategoryVo> buildTree(List<CategoryVo> categoryVoList) {
        //创建出一个集合，用于存放组装好的树形结构
        ArrayList<CategoryVo> tree = new ArrayList<>();
        //遍历categoryVoList
        for (CategoryVo categoryVo : categoryVoList) {
            //判断当前的Vo中，是否是父节点
            if (categoryVo.getParentId().longValue() == 0){
                //如果当前节点是父节点，那么就去寻找子节点并添加到children属性中
                //使用findAndAddChildren方法，这是一个递归方法
                //他会去遍历categoryVoList，从中找出categoryVo所对应的子节点，并设置进去
                categoryVo = findAndAddChildren(categoryVo,categoryVoList);
                //我们将返回的categoryVo对象（此时已经被组装成一个完整的树形结构），添加到tree集合中
                tree.add(categoryVo);
            }
        }
        //将组装好的树形结构集合，返回
        return tree;
    }

    /**
     * 递归方法，用于寻找子节点，并且添加children属性
     * @param root vo对象
     * @param categoryVoList vo集合
     * @return
     */
    private CategoryVo findAndAddChildren(CategoryVo root, List<CategoryVo> categoryVoList) {
        //遍历categoryVoList，寻找root节点的子节点
        for (CategoryVo vo : categoryVoList) {
            //若vo的父id等于categoryVo的id，那么就认为vo是categoryVo的子节点
            if (vo.getParentId().longValue() == root.getId().longValue()){
                //此时有可能vo也有子节点，因此这里使用递归，给vo也设置上children属性
                vo = findAndAddChildren(vo,categoryVoList);
                //给传进来的root节点设置children属性为vo
                //不能直接setChildren，因为Children需要List<CategoryVo>类型
                //我们直接获取出List，手动给List添加元素
                root.getChildren().add(vo);
            }
        }
        return root;
    }
}
